package short_semester.questionnaire_planet.service.analyse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import short_semester.questionnaire_planet.dao.*;
import short_semester.questionnaire_planet.entity.User;


import short_semester.questionnaire_planet.exception.NoUserOrQuestionnaireException;
import short_semester.questionnaire_planet.pojo.*;

import short_semester.questionnaire_planet.request.fillRequest.ip.IPBody;
import short_semester.questionnaire_planet.response.AnalyseController.*;
import short_semester.questionnaire_planet.response.fillResponse.QuestionRecordResponse;
import short_semester.questionnaire_planet.service.editService.*;


import java.util.*;

@Service
public class QuestionnaireRecordService {
    @Autowired
    QuestionnaireDao questionnaireDao;
    
    @Autowired
    QuestionnaireRecordDao questionnaireRecordDao;
    
    @Autowired
    QuestionService questionService;

    @Autowired
    UserDao userDao;
    
    @Autowired
    QuestionSequenceRecordDao sequenceRecordDao;
    
    @Autowired
    QuestionSequenceDao sequenceDao;
    
    @Autowired
    SingleChoiceQuestionRecordDao singleChoiceQuestionRecordDao;
    @Autowired
    MultipleChoiceQuestionRecordDao multipleChoiceQuestionRecordDao;
//    @Autowired
//    MultiChoiceOptionRecordDao multiChoiceOptionRecordDao;
    @Autowired
    FillBlankQuestionRecordDao fillBlankQuestionRecordDao;
    @Autowired
    ScoreQuestionRecordDao scoreQuestionRecordDao;
    
    @Autowired
    SingleChoiceQuestionRecordService singleChoiceQuestionRecordService;
    @Autowired
    MultipleChoiceQuestionRecordService multipleChoiceQuestionRecordService;
    @Autowired
    FillBlankQuestionRecordService fillBlankQuestionRecordService;
    @Autowired
    ScoreQuestionRecordService scoreQuestionRecordService;

    @Autowired
    SingleChoiceQuestionService singleChoiceQuestionService;
    @Autowired
    MultiChoiceQuestionService multiChoiceQuestionService;
    
    //获取问卷答题数量的接口
    public int getQuestionnaireCount(Questionnaire questionnaire){
        return questionnaire.getCount();
//        return questionnaireRecordDao.countByQuestionnaireAndIsSubmittedTrue(questionnaire);
    }
    
    //问卷分析接口
    public QAnalyseResponse getAnalyseInfoResponse(Integer questionnaireId){
        
        Questionnaire questionnaire = questionnaireDao.getById(questionnaireId);
        QAnalyseResponse response = new QAnalyseResponse(questionnaire);
//        response.setQuestionnaireTitle(questionnaire.getTitle());
//        response.setQuestionnaireCount(questionnaire.getCount());
        Collection<Object> questions = questionService.getQuestions(questionnaire);
        for (Object o: questions){
            response.addQuestion(o);
        }
        
        return response;
    }

    public QuestionnaireRecord getByUserIdAndQuestionnaireId(
            Integer userId,
            Integer questionnaireId
    ) throws Exception {
        Optional<QuestionnaireRecord> result;
        Optional<User> user = userDao.findById(userId);
        Optional<Questionnaire> questionnaire = questionnaireDao.findById(questionnaireId);
        if (user.isPresent() && questionnaire.isPresent()) {
            result = questionnaireRecordDao.findByUserAndQuestionnaire(
                    user.get(), questionnaire.get()
            );
            return result.orElse(null);
        }
        else {
            throw new Exception("没有该用户或者该问卷");
        }
    }

    public QuestionnaireRecord getByUuidAndQuestionnaireId(
            String uuid,
            Integer questionnaireId
    ) throws Exception {
        Optional<QuestionnaireRecord> result;
        Optional<Questionnaire> questionnaire = questionnaireDao.findById(questionnaireId);
        if (!questionnaire.isPresent())
            throw new Exception("没有该Id对应的问卷");
        else {
            result = questionnaireRecordDao.findByUuidAndQuestionnaire(uuid, questionnaire.get());
            return result.orElse(null);
        }
    }

    public QuestionnaireRecord checkExistence(
            Integer userId,
            Integer questionnaireId,
            String uuid
    ) throws NoUserOrQuestionnaireException {
        if (userId != null) {
            Optional<User> user = userDao.findById(userId);
            Optional<Questionnaire> questionnaire = questionnaireDao.findById(questionnaireId);
            if(!user.isPresent()) {
                throw new NoUserOrQuestionnaireException("没有该id对应的用户");
            }
            else if(!questionnaire.isPresent()) {
                throw new NoUserOrQuestionnaireException("没有该id对应的问卷");
            }
            else {
                Optional<QuestionnaireRecord> result = questionnaireRecordDao.
                        findByUserAndQuestionnaire(user.get(), questionnaire.get());
                if (!result.isPresent()) {
                    QuestionnaireRecord qr = new QuestionnaireRecord();
                    qr.setQuestionnaire(questionnaire.get());
                    qr.setUser(user.get());
                    questionnaireRecordDao.save(qr);
                    return qr;
                }
                else return result.get();
            }
        }
        else {
            if (uuid == null)
                throw new NoUserOrQuestionnaireException("uuid和id不能同时为null");
            Optional<Questionnaire> questionnaire = questionnaireDao.findById(questionnaireId);
            if (!questionnaire.isPresent())
                throw new NoUserOrQuestionnaireException("没有该id对应的问卷");

            Optional<QuestionnaireRecord> result = questionnaireRecordDao.
                    findByUuidAndQuestionnaire(uuid, questionnaire.get());
            if (!result.isPresent()) {
                QuestionnaireRecord qr = new QuestionnaireRecord();
                qr.setQuestionnaire(questionnaire.get());
                qr.setUuid(uuid);
                questionnaireRecordDao.save(qr);
                return qr;
            }
            else return result.get();

        }
    }

    public Integer submit(
            Integer userId,
            Integer questionnaireId,
            String uuid,
            IPBody ipBody,
            String type
    ) throws Exception {

        Optional<Questionnaire>  questionnaire = questionnaireDao.findById(questionnaireId);
        if (userId != null) {
            Optional<User> user = userDao.findById(userId);
            if (!user.isPresent() || !questionnaire.isPresent())
                throw new NoUserOrQuestionnaireException("没有该用户或者问卷");
            Optional<QuestionnaireRecord> ret = questionnaireRecordDao
                    .findByUserAndQuestionnaire(user.get(), questionnaire.get());
            if (!ret.isPresent())
                throw new NoUserOrQuestionnaireException("该用户没有填写过该文卷");
            QuestionnaireRecord questionnaireRecord = ret.get();
            questionnaireRecord.setIsSubmitted(true);
            questionnaireRecord.setSubmitDate(new Date());
            questionnaireRecord.setConsTime((questionnaireRecord.getSubmitDate().getTime()-questionnaireRecord.getCreatedDate().getTime())/1000);
            submittedQuestion(questionnaireRecord);
            if(ipBody!=null){
                questionnaireRecord.setIPBody(ipBody);
            }
            
            questionnaireDao.submitQuestionnaire(questionnaireId);
            if(type!=null&&type.equals("exam")){
                //计算分数
                questionnaireRecord.setGrade(this.compute(questionnaireRecord));
            }
            questionnaireRecord = questionnaireRecordDao.save(questionnaireRecord);
            return questionnaireRecord.getId();
        }
        else if (uuid != null) {
            if (!questionnaire.isPresent())
                throw new NoUserOrQuestionnaireException("没有该问卷");
            Optional<QuestionnaireRecord> ret = questionnaireRecordDao
                    .findByUuidAndQuestionnaire(uuid, questionnaire.get());
            if (!ret.isPresent())
                throw new NoUserOrQuestionnaireException("该用户没有填写过该文卷");

            QuestionnaireRecord questionnaireRecord = ret.get();
            questionnaireRecord.setIsSubmitted(true);
            questionnaireRecord.setSubmitDate(new Date());
            questionnaireRecord.setConsTime((questionnaireRecord.getSubmitDate().getTime()-questionnaireRecord.getCreatedDate().getTime())/1000);
            submittedQuestion(questionnaireRecord);
            questionnaireDao.submitQuestionnaire(questionnaireId);

            if(type!=null&&type.equals("exam")){
                //计算分数
                questionnaireRecord.setGrade(this.compute(questionnaireRecord));
            }
            
            questionnaireRecord = questionnaireRecordDao.save(questionnaireRecord);
            return questionnaireRecord.getId();
        }
        else
            throw new Exception("id和uuid不能同时为null");
        
    }
    
    public void submittedQuestion(QuestionnaireRecord record){
        singleChoiceQuestionRecordService.submitRecord(record);
        multipleChoiceQuestionRecordService.submitRecord(record);
        fillBlankQuestionRecordService.submitRecord(record);
        scoreQuestionRecordService.submitRecord(record);
    }
    
    //获取所有人的填写信息
    public List<RecordsResponse> getRecordsResponse(Integer questionnaireId){
        List<RecordsResponse> responses = new LinkedList<>();
        
        List<QuestionnaireRecord> questionnaireRecordList = questionnaireRecordDao.findByQuestionnaireAndIsSubmittedTrue(new Questionnaire(questionnaireId));
        
        for (QuestionnaireRecord record: questionnaireRecordList){
            responses.add(new RecordsResponse(record));
        }
        
        return responses;
    }
    
    //获取单个人的填写信息
    public RecordResponse getRecordResponse(Integer recordId){
        QuestionnaireRecord record = questionnaireRecordDao.getById(recordId);
        RecordResponse response = new RecordResponse(record);
        response.setRank(1+questionnaireRecordDao.countByQuestionnaireAndIsSubmittedTrueAndGradeAfter(record.getQuestionnaire(),record.getGrade()));
        response.setCount(record.getQuestionnaire().getCount());
        response.setQuestions(getUserQuestionRecord(record));
        return response;
    }
    
    public List<QuestionRecordAnalyseResponse> getUserQuestionRecord(QuestionnaireRecord record){
        
        Questionnaire questionnaire = record.getQuestionnaire();
        List<QuestionRecordAnalyseResponse> questionRecordAnalyseResponseList = new LinkedList<>();
        //获取问卷的所有题目信息
        Collection<Object> questions = questionService.getQuestions(questionnaire);
        for (Object o: questions){
            if(o instanceof SingleChoiceQuestion){
                SingleChoiceQuestion question = (SingleChoiceQuestion)o;
                //设置题目信息
                QuestionRecordAnalyseResponse questionRecordAnalyseResponse = new QuestionRecordAnalyseResponse(question);
                
                //拿到对应题目记录
                SingleChoiceQuestionRecord questionRecord = singleChoiceQuestionRecordDao.findByQuestionnaireRecordAndSingleChoiceQuestion(record,question).get();
                if(questionRecord.getAnswer()==null){
                    questionRecordAnalyseResponse.setIsFinish(false);
                }else{
                    questionRecordAnalyseResponse.setIsFinish(true);
                }
                //获取答案
                questionRecordAnalyseResponse.getAnswers().add(questionRecord.getAnswer());
                //加载选项
                for (SingleChoiceOption option : question.getOptions()) {
                    OptionRecordAnalyseResponse optionRecordAnalyseResponse = new OptionRecordAnalyseResponse();
                    optionRecordAnalyseResponse.setText(option.getText());
                    optionRecordAnalyseResponse.setDescription(option.getDescription());
                    optionRecordAnalyseResponse.setIsChoosed(questionRecordAnalyseResponse.getAnswers().contains(option.getId()));
                    optionRecordAnalyseResponse.setIsCorrect(option.getIsCorrect());
                    questionRecordAnalyseResponse.getOptions().add(optionRecordAnalyseResponse);
                }
                
                questionRecordAnalyseResponseList.add(questionRecordAnalyseResponse);
            }else if (o instanceof MultiChoiceQuestion){
                MultiChoiceQuestion question = (MultiChoiceQuestion) o;
                //设置题目信息
                QuestionRecordAnalyseResponse questionRecordAnalyseResponse = new QuestionRecordAnalyseResponse(question);

                //拿到对应题目记录
                MultiChoiceQuestionRecord questionRecord = multipleChoiceQuestionRecordDao.findByQuestionnaireRecordAndMultiChoiceQuestion(record,question).get();
                //获取答案

                questionRecordAnalyseResponse.getAnswers().addAll(questionRecord.getAnswer());
                if(questionRecordAnalyseResponse.getAnswers().isEmpty()){
                    questionRecordAnalyseResponse.setIsFinish(false);
                }else{
                    questionRecordAnalyseResponse.setIsFinish(true);
                }
                //加载选项
                for (MultiChoiceOption option : question.getOptions()) {
                    OptionRecordAnalyseResponse optionRecordAnalyseResponse = new OptionRecordAnalyseResponse();
                    optionRecordAnalyseResponse.setText(option.getText());
                    optionRecordAnalyseResponse.setDescription(option.getDescription());
                    optionRecordAnalyseResponse.setIsChoosed(questionRecordAnalyseResponse.getAnswers().contains(option.getId()));
                    optionRecordAnalyseResponse.setIsCorrect(option.getIsCorrect());
                    questionRecordAnalyseResponse.getOptions().add(optionRecordAnalyseResponse);
                }
                
                questionRecordAnalyseResponseList.add(questionRecordAnalyseResponse);
            }else if(o instanceof FillBlankQuestion){
                FillBlankQuestion question = (FillBlankQuestion) o;
                //设置题目信息
                QuestionRecordAnalyseResponse questionRecordAnalyseResponse = new QuestionRecordAnalyseResponse(question);

                //拿到对应题目记录
                FillBlankQuestionRecord questionRecord = fillBlankQuestionRecordDao.findByQuestionnaireRecordAndFillBlankQuestion(record,question).get();
                if(questionRecord.getAnswer()==null){
                    questionRecordAnalyseResponse.setIsFinish(false);
                }else{
                    questionRecordAnalyseResponse.setIsFinish(true);
                    //获取答案
                    questionRecordAnalyseResponse.setContent(questionRecord.getAnswer());
                }
                
                
                questionRecordAnalyseResponseList.add(questionRecordAnalyseResponse);
            }else if(o instanceof ScoreQuestion){
                ScoreQuestion question = (ScoreQuestion) o;
                //设置题目信息
                QuestionRecordAnalyseResponse questionRecordAnalyseResponse = new QuestionRecordAnalyseResponse(question);

                //拿到对应题目记录
                ScoreQuestionRecord questionRecord = scoreQuestionRecordDao.findByQuestionnaireRecordAndScoreQuestion(record,question).get();
                if(questionRecord.getAnswer()==null){
                    questionRecordAnalyseResponse.setIsFinish(false);
                }else{
                    questionRecordAnalyseResponse.setIsFinish(true);
                    //获取答案
                }
                questionRecordAnalyseResponse.getAnswers().add(questionRecord.getAnswer());
                //加载选项
                for (ScoreOption option : question.getOptions()) {
                    OptionRecordAnalyseResponse optionRecordAnalyseResponse = new OptionRecordAnalyseResponse();
                    optionRecordAnalyseResponse.setText(option.getText());
//                    userOptionResponse.setDescription(option.getDescription());
                    optionRecordAnalyseResponse.setScore(option.getScore());
                    optionRecordAnalyseResponse.setIsChoosed(questionRecordAnalyseResponse.getAnswers().contains(option.getId()));
                    questionRecordAnalyseResponse.getOptions().add(optionRecordAnalyseResponse);
                }
                
                questionRecordAnalyseResponseList.add(questionRecordAnalyseResponse);
            }
        }
        
        return questionRecordAnalyseResponseList;
    }
    
    //初始化用户填写记录并将初始默认值设给题目记录表
    public void initQuestionRecord(QuestionnaireRecord questionnaireRecord){
        int sequence = 0;
        for (Object o : questionService.getQuestionsRandom(questionnaireRecord.getQuestionnaire())) {
            if(o instanceof SingleChoiceQuestion){

                SingleChoiceQuestion question = (SingleChoiceQuestion)o;
                //记录顺序
                QuestionSequenceRecord sequenceRecord = new QuestionSequenceRecord(
                        questionnaireRecord, question.getType(),sequence,question.getId());
                sequenceRecordDao.save(sequenceRecord);
                //记录选项顺序和答案
                SingleChoiceQuestionRecord questionRecord = new SingleChoiceQuestionRecord(questionnaireRecord,question,sequence);
                
                
                for (SingleChoiceOption option : question.getOptions()) {
                    questionRecord.getOptionSequence().add(option.getId());
                    if(option.getIsDefault()){
                        questionRecord.setAnswer(option.getId());
                        break;
                    }
                }
                //保存
                singleChoiceQuestionRecordDao.save(questionRecord);
            }else if(o instanceof MultiChoiceQuestion){

                MultiChoiceQuestion question = (MultiChoiceQuestion) o;
                //记录顺序
                QuestionSequenceRecord sequenceRecord = new QuestionSequenceRecord(
                        questionnaireRecord, question.getType(),sequence,question.getId());
                sequenceRecordDao.save(sequenceRecord);
                //记录选项顺序和答案
                MultiChoiceQuestionRecord questionRecord = new MultiChoiceQuestionRecord(questionnaireRecord,question,sequence);

                for (MultiChoiceOption option : question.getOptions()) {
                    questionRecord.getOptionSequence().add(option.getId());
                    if(option.getIsDefault()){
                        questionRecord.getAnswer().add(option.getId());
                    }
                }
                //保存
                multipleChoiceQuestionRecordDao.save(questionRecord);

            }else if(o instanceof FillBlankQuestion){

                FillBlankQuestion question = (FillBlankQuestion) o;
                //记录顺序
                QuestionSequenceRecord sequenceRecord = new QuestionSequenceRecord(
                        questionnaireRecord, question.getType(),sequence,question.getId());
                sequenceRecordDao.save(sequenceRecord);
                
                //记录选项顺序和答案
                FillBlankQuestionRecord questionRecord = new FillBlankQuestionRecord(questionnaireRecord,question,sequence);
                questionRecord.setAnswer(question.getDefaultValue());
                fillBlankQuestionRecordDao.save(questionRecord);
            }else if(o instanceof ScoreQuestion){

                ScoreQuestion question = (ScoreQuestion) o;
                //记录顺序
                QuestionSequenceRecord sequenceRecord = new QuestionSequenceRecord(
                        questionnaireRecord, question.getType(),sequence,question.getId());
                sequenceRecordDao.save(sequenceRecord);

                //记录选项顺序和答案
                ScoreQuestionRecord questionRecord = new ScoreQuestionRecord(questionnaireRecord,question,sequence);
                for (ScoreOption option : question.getOptions()) {
                    if(option.getIsDefault()){
                        questionRecord.setAnswer(option.getId());
                        break;
                    }
                }
                
                scoreQuestionRecordDao.save(questionRecord);
            }
            ++sequence;
        }
    }
    
    //获取用户填写记录
    public List<QuestionRecordResponse> getQuestionRecordByRecord(QuestionnaireRecord record){
        List<QuestionRecordResponse> questionRecordResponseList = new LinkedList<>();
        
        for (QuestionSequenceRecord sequenceRecord : sequenceRecordDao.findByQuestionnaireRecordOrderBySequence(record)){
            switch (sequenceRecord.getType()){
                case "radio":
                    questionRecordResponseList.add(singleChoiceQuestionRecordService.getRecord(record,sequenceRecord.getQuestionId()));
                    break;
                case "checkbox":
                    questionRecordResponseList.add(multipleChoiceQuestionRecordService.getRecord(record,sequenceRecord.getQuestionId()));
                    break;
                case "completion":
                    questionRecordResponseList.add(fillBlankQuestionRecordService.getRecord(record,sequenceRecord.getQuestionId()));
                    break;
                case "score":
                    questionRecordResponseList.add(scoreQuestionRecordService.getRecord(record,sequenceRecord.getQuestionId()));
                    break;
            }
        }
        
        return  questionRecordResponseList;
    }
    
    public int compute(QuestionnaireRecord record){
        int grade = 0;
        for (QuestionSequenceRecord sequenceRecord : sequenceRecordDao.findByQuestionnaireRecord(record)){
            switch (sequenceRecord.getType()){
                case "radio":
                    grade+=singleChoiceQuestionRecordService.compute(record,sequenceRecord.getQuestionId());
                    break;
                case "checkbox":
                    grade+=multipleChoiceQuestionRecordService.compute(record,sequenceRecord.getQuestionId());
                    break;
                case "completion":
                    grade+=fillBlankQuestionRecordService.compute(record,sequenceRecord.getQuestionId());
                    break;
//                case "score":
//                    grade+=scoreQuestionRecordService.compute(record,sequenceRecord.getQuestionId());
//                    break;
            }
        }
        
        return grade;
    }
}
